﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.IO;
using CookComputing.XmlRpc;

namespace WordPress.Net
{

    #region WorPress API structs
    [XmlRpcMissingMapping(MappingAction.Ignore)]
    public struct MediaObject
    {
        public string name;
        public string type;
        public byte[] bits;
    }

    public struct MediaObjectInfo
    {
        public string url;

    }
    /// <summary>
    /// Custom field info attached to a blog item.
    /// </summary>
    public struct CustomField
    {
        public string id;
        public string key;
        public string value;

    }
    /// <summary>
    /// Page bucket.
    /// </summary>
    public struct Page
    {
        public DateTime dateCreated;
        public string userid;
        public int page_id;
        public string page_status;
        public string description;
        public string title;
        public string link;
        public string permaLink;
        public string[] categories;
        public string excerpt;
        public string text_more;
        public int mt_allow_comments;
        public int mt_allow_pings;
        public string wp_slug;
        public string wp_password;
        public string wp_author;
        public object wp_page_parent_id;
        public string wp_page_parent_title;
        public int wp_page_order;
        public string wp_author_id;
        public string wp_author_display_name;
        public DateTime date_created_gmt;
        public CustomField[] custom_fields;
        public string wp_page_template;
    }
    /// <summary>
    /// A comment on a blog item
    /// </summary>
    public struct Comment
    {
        public DateTime date_created_gmt;
        public string user_id;
        public string comment_id;
        public string parent;
        public string status;
        public string content;
        public string link;
        public string post_id;
        public string post_title;
        public string author;
        public string author_url;
        public string author_email;
        public string author_ip;
        public string type;
    }

    /// <summary> 
    /// This struct represents information about a user's blog. 
    /// </summary> 
    [XmlRpcMissingMapping(MappingAction.Ignore)]
    public struct UserBlog
    {
        public string url;
        public string blogid;
        public string blogName;
    }


    /// <summary> 
    /// This struct represents information about a user. 
    /// </summary> 
    [XmlRpcMissingMapping(MappingAction.Ignore)]
    public struct UserInfo
    {
        public string url;
        public string blogid;
        public string blogName;
        public string firstname;
        public string lastname;
        public string email;
        public string nickname;
    }
    /// <summary>
    /// Filtering structure for getting comments.
    /// </summary>
    [XmlRpcMissingMapping(MappingAction.Ignore)]
    public struct CommentFilter
    {
        public string status;
        public int post_id;
        public int number;
        public int offset;

    }
    [XmlRpcMissingMapping(MappingAction.Ignore)]
    public struct TagInfo
    {
        public string id;
        public string name;
        public string count;
        public string slug;
        public string html_url;
        public string rss_url;

    }

    /// <summary> 
    /// This struct represents the information about a category that you can insert into your blog. 
    /// </summary> 
    [XmlRpcMissingMapping(MappingAction.Ignore)]
    public struct Category
    {
        public string name;
        public string slug;
        public string parent_id;
        public string description;
    }

    /// <summary> 
    /// This struct represents the information about a category returned from the getCategories method. 
    /// </summary> 
    [XmlRpcMissingMapping(MappingAction.Ignore)]
    public struct CategoryInfo
    {
        public int categoryid;
        public int parentid;
        public string description;
        public string categoryName;
        public string htmlurl;
        public string rssurl;
    }

    /// <summary> 
    /// This struct represents the information about a post that could be returned by the 
    /// EditPost(), GetRecentPosts() and GetPost() methods. 
    /// </summary> 
    [XmlRpcMissingMapping(MappingAction.Ignore)]
    public struct Post
    {
        public DateTime dateCreated;
        public string description;
        public string title;
        public string postid;
        public string[] categories;
        /// <summary>
        /// These are the tags of the post separated with a ','. Use the Split function to convert to an array.
        /// </summary>
        public string mt_keywords;
    }
    #endregion

    /// <summary> 
    /// WordPress 2.9.1 XML-RPC API wrapper for .Net.
    /// </summary> 
    [XmlRpcUrl(WP.BlogUrl)]
    class WP : XmlRpcClientProtocol
    {
        /// <summary>
        /// This is the full url to the XML-RPC endpoint.
        /// </summary>
        public const string BlogUrl = "http://www.howtoflo.de/xmlrpc.php";
        /// <summary>
        /// The username with which you usually log in.
        /// </summary>
        public const string Username = "admin";

        /// <summary>
        /// The corresponding password.
        /// </summary>
        public const string Password = "passwort.net";
        public const int BlogID = 0; //doesn't matter in general



        #region GetTags

        /// <summary>
        /// Gets all the tags defined in WordPress.
        /// </summary>
        /// <returns></returns>
        public TagInfo[] GetTags()
        {
            return GetTags(BlogID, Username, Password);
        }

        [XmlRpcMethod("wp.getTags")]
        public TagInfo[] GetTags(int blogid, string username, string password)
        {
            return (TagInfo[])this.Invoke("GetTags", new object[] { blogid, username, password });

        }
        #endregion

        #region GetRecentPosts
        /// <summary> 
        /// Returns the most recent draft and non-draft blog posts sorted in descending order by publish date. 
        /// </summary> 
        public Post[] GetRecentPosts(int numberOfPosts)
        {
            return GetRecentPosts(BlogID, Username, Password, numberOfPosts);
        }

        /// <summary>
        /// Returns the most recent draft and non-draft blog posts sorted in descending order by publish date.
        /// </summary>
        /// <param name="blogid">The blogid.</param>
        /// <param name="username">The username.</param>
        /// <param name="password">The password.</param>
        /// <param name="numberOfPosts">The number of posts to return. The maximum value is 20.</param>
        /// <returns></returns>
        [XmlRpcMethod("metaWeblog.getRecentPosts")]
        public Post[] GetRecentPosts(int blogid, string username, string password, int numberOfPosts)
        {

            return (Post[])this.Invoke("GetRecentPosts", new object[] { blogid, username, password, numberOfPosts });
        }

        #endregion

        #region NewPost
        /// <summary> 
        /// Posts a new entry to a blog. 
        /// </summary> 
        /// <param name="content">The content.</param>
        /// <param name="publish">If false, this is a draft post.</param>
        /// <returns>The postid of the newly-created post.</returns>
        public string NewPost(Post content, bool publish)
        {
            return NewPost(BlogID, Username, Password, content, publish);
        }

        /// <summary>
        /// Posts a new entry to a blog.
        /// </summary>
        /// <param name="blogid">This should be the string MyBlog, which indicates that the post is being created in the user’s blog.</param>
        /// <param name="username">The name of the user’s space.</param>
        /// <param name="password">The user’s secret word.</param>
        /// <param name="content">The content.</param>
        /// <param name="publish">If false, this is a draft post.</param>
        /// <returns>The postid of the newly-created post.</returns>
        [XmlRpcMethod("metaWeblog.newPost")]
        public string NewPost(int blogid, string username, string password, Post content, bool publish)
        {
            return (string)this.Invoke("NewPost", new object[] { blogid, username, password, content, publish });
        }

        #endregion

        #region EditPost
        /// <summary>
        /// Edits an existing entry on a blog.
        /// </summary>
        /// <param name="content">The content.</param>
        /// <param name="publish">If false, this is a draft post.</param>
        /// <returns>Always returns true.</returns>
        public bool EditPost(Post content, bool publish)
        {
            return EditPost(Convert.ToInt16(content.postid), Username, Password, content, publish);
        }

        /// <summary>
        /// Edits an existing entry on a blog.
        /// </summary>
        /// <param name="postid">The ID of the post to update.</param>
        /// <param name="username">The name of the user’s space.</param>
        /// <param name="password">The user’s secret word.</param>
        /// <param name="content">The content.</param>
        /// <param name="publish">If false, this is a draft post.</param>
        /// <returns>Always returns true.</returns>
        [XmlRpcMethod("metaWeblog.editPost")]
        public bool EditPost(int postid, string username, string password, Post content, bool publish)
        {
            return (bool)this.Invoke("EditPost", new object[] { postid, username, password, content, publish });
        }

        #endregion

        #region DeletePost
        /// <summary>
        /// Deletes a post from the blog.
        /// </summary>
        /// <param name="postid">The ID of the post to delete.</param>
        /// <returns>Always returns true.</returns>
        public bool DeletePost(string postid)
        {
            return DeletePost("", postid, Username, Password, false);
        }

        /// <summary>
        /// Deletes a post from the blog.
        /// </summary>
        /// <param name="appKey">This value is ignored.</param>
        /// <param name="postid">The ID of the post to delete.</param>
        /// <param name="username">The name of the user’s space.</param>
        /// <param name="password">The user’s secret word.</param>
        /// <param name="publish">This value is ignored.</param>
        /// <returns>Always returns true.</returns>
        [XmlRpcMethod("blogger.deletePost")]
        public bool DeletePost(string appKey, string postid, string username, string password, bool publish)
        {
            return (bool)this.Invoke("DeletePost", new object[] { appKey, postid, username, password, publish });
        }

        #endregion

        #region GetComments
        public Comment[] GetComments(CommentFilter filter)
        {
            return GetComments(BlogID, Username, Password, filter);
        }
        [XmlRpcMethod("wp.getComments")]
        public Comment[] GetComments(int blogid, string username, string password, CommentFilter filter)
        {
            return (Comment[])this.Invoke("GetComments", new object[] { blogid, username, password, filter });

        }

        #endregion

        #region GetUserInfo
        /// <summary>
        /// Returns basic user info (name, e-mail, userid, and so on).
        /// </summary>
        public UserInfo GetUserInfo()
        {
            return GetUserInfo("", Username, Password);
        }


        /// <summary>
        /// Returns basic user info (name, e-mail, userid, and so on).
        /// </summary>
        /// <param name="appKey">This value is ignored.</param>
        /// <param name="username">The name of the user’s space.</param>
        /// <param name="password">The password.</param>
        /// <returns>
        /// A struct containing profile information about the user.
        /// Each struct will contain the following fields: nickname, userid, url, e-mail,
        /// lastname, and firstname.
        /// </returns>
        [XmlRpcMethod("blogger.getUserInfo")]
        public UserInfo GetUserInfo(string appKey, string username, string password)
        {
            return (UserInfo)this.Invoke("GetUserInfo", new object[] { appKey, username, password });
        }
        #endregion

        #region GetUserBlogs
        public void GetUserBlogs()
        {
            throw new ApplicationException("This method is only useful as part of the µ edition of WordPress and is not implemented here.");
        }
        #endregion

        #region GetPost
        /// <summary>
        /// Returns a specific entry from a blog.
        /// </summary>
        /// <param name="postid">The ID of the post to fetch.</param>
        /// <returns>The post item.</returns>
        public Post GetPost(string postid)
        {
            return GetPost(postid, Username, Password);
        }

        /// <summary> 
        /// Returns a specific entry from a blog. 
        /// </summary> 
        /// <param name="postid"> The ID of the post to fetch. </param> 
        /// <param name="username"> The name of the user’s space. </param> 
        /// <param name="password"> The user’s secret word. </param> 
        /// <returns> The post item. </returns> 
        [XmlRpcMethod("metaWeblog.getPost")]
        public Post GetPost(string postid, string username, string password)
        {
            return (Post)this.Invoke("GetPost", new object[] { postid, username, password });
        }
        #endregion

        //#region GetCategories
        ///// <summary> 
        ///// Returns the list of categories that have been used in the blog. 
        ///// </summary> 
        //public Category[] GetCategories()
        //{
        //    return GetCategories(BlogID, Username, Password);
        //}

        ///// <summary> 
        ///// Returns the list of categories that have been used in the blog. 
        ///// </summary> 
        ///// <param name="blogid"> The blog id. </param> 
        ///// <param name="username"> The name of the user’s space. </param> 
        ///// <param name="password"> The user’s secret word. </param> 
        ///// <returns> An array of structs that contains one struct for each category. Each category struct will contain a description field that contains the name of the category. </returns> 
        //[XmlRpcMethod("metaWeblog.getCategories")]
        //public Category[] GetCategories(string blogid, string username, string password)
        //{
        //    return (Category[])this.Invoke("GetCategories", new object[] { blogid, username, password });
        //}


        //#endregion

        #region GetPage
        public Page GetPage(string pageid)
        {
            return GetPage(BlogID, pageid, Username, Password);
        }

        [XmlRpcMethod("wp.getPage")]
        public Page GetPage(int blogid, string pageid, string username, string password)
        {
            return (Page)this.Invoke("GetPage", new object[] { blogid, pageid, username, password });
        }
        #endregion

        #region GetPages
        /// <summary>
        /// Gets pages from the blog.
        /// </summary>
        /// <param name="numberofpages">The number of pages to fetch.</param>
        /// <returns></returns>
        public Page[] GetPages(int numberofpages)
        {
            return GetPages(BlogID, Username, Password, numberofpages);
        }

        /// <summary>
        /// Gets pages from the blog.
        /// </summary>
        /// <param name="blogid">The blogid.</param>
        /// <param name="username">The username.</param>
        /// <param name="password">The password.</param>
        /// <param name="numberofpages">The number of pages to fetch.</param>
        /// <returns></returns>
        [XmlRpcMethod("wp.getPages")]
        public Page[] GetPages(int blogid, string username, string password, int numberofpages)
        {
            return (Page[])this.Invoke("GetPages", new object[] { blogid, username, password, numberofpages });
        }
        #endregion

        #region NewMediaObject
        public MediaObjectInfo NewMediaObject(MediaObject mediaObject)
        {
            return NewMediaObject(BlogID, Username, Password, mediaObject);
        }

        [XmlRpcMethod("metaWeblog.newMediaObject")]
        public MediaObjectInfo NewMediaObject(int blogid, string username, string password, MediaObject mediaObject)
        {
            return (MediaObjectInfo)this.Invoke("NewMediaObject", new object[] { blogid, username, password, mediaObject });
        }
        #endregion

        #region Image conversion utilities
        public static byte[] ConvertImageToByteArray(Image imageToConvert, ImageFormat formatOfImage)
        {
            byte[] Ret;
            using (MemoryStream ms = new MemoryStream())
            {
                imageToConvert.Save(ms, formatOfImage);
                Ret = ms.ToArray();
            }
            return Ret;
        }

        public static Image ConvertByteArrayToImage(byte[] byteArray)
        {
            if (byteArray != null)
            {
                MemoryStream ms = new MemoryStream(byteArray, 0,
                byteArray.Length);
                ms.Write(byteArray, 0, byteArray.Length);
                return Image.FromStream(ms, true);
            }
            return null;
        }
        #endregion

        #region NewCategory
        /// <summary> 
        /// Posts a new entry to a blog. 
        /// </summary> 
        /// <param name="category">The category to be added.</param>
        /// <returns>The category id of the newly-created category.</returns>
        public int NewCategory(Category category)
        {
            return NewCategory(BlogID, Username, Password, category);
        }

        /// <summary>
        /// Posts a new category to a blog.
        /// </summary>
        /// <param name="blogid">This should be the string MyBlog, which indicates that the post is being created in the user’s blog.</param>
        /// <param name="username">The name of the user’s space.</param>
        /// <param name="password">The user’s secret word.</param>
        /// <param name="category">The category to add.</param>
        /// <returns>The postid of the newly-created category.</returns>
        [XmlRpcMethod("wp.newCategory")]
        public int NewCategory(int blogid, string username, string password, Category category)
        {
            return (int)this.Invoke("NewCategory", new object[] { blogid, username, password, category });
        }
        #endregion

        #region DeleteCategory
        /// <summary>
        /// Deletes a category from a blog.
        /// </summary>
        /// <param name="categoryid">The categoryid to be deleted.</param>
        public void DeleteCategory(int categoryid)
        {
            DeleteCategory(BlogID, Username, Password, categoryid);
        }

        /// <summary>
        /// Deletes a category from a blog.
        /// </summary>
        /// <param name="blogid">This should be the string MyBlog, which indicates that the post is being created in the user’s blog.</param>
        /// <param name="username">The name of the user’s space.</param>
        /// <param name="password">The user’s secret word.</param>
        /// <param name="categoryid">The categoryid to be deleted.</param>
        [XmlRpcMethod("wp.deleteCategory")]
        public void DeleteCategory(int blogid, string username, string password, int categoryid)
        {
            this.Invoke("DeleteCategory", new object[] { blogid, username, password, categoryid });
        }
        #endregion

        #region GetCategories
        /// <summary>
        /// Deletes a category from a blog.
        /// </summary>
        /// <param name="categoryid">The categoryid to be deleted.</param>
        public CategoryInfo[] GetCategories()
        {
            return GetCategories(BlogID, Username, Password);
        }

        /// <summary>
        /// Deletes a category from a blog.
        /// </summary>
        /// <param name="blogid">This should be the string MyBlog, which indicates that the post is being created in the user’s blog.</param>
        /// <param name="username">The name of the user’s space.</param>
        /// <param name="password">The user’s secret word.</param>
        /// <param name="categoryid">The categoryid to be deleted.</param>
        [XmlRpcMethod("wp.getCategories")]
        public CategoryInfo[] GetCategories(int blogid, string username, string password)
        {
            return (CategoryInfo[])this.Invoke("GetCategories", new object[] { blogid, username, password });
        }
        #endregion
    }

}
